home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Applications / Graphics / MapMaker / Source / proj.c < prev    next >
Text File  |  1990-12-04  |  9KB  |  392 lines

  1. /*
  2. ** proj.c
  3. ** map projection calculation and generation routines
  4. ** for project : MapMaker  
  5. ** using NeXTStep and mach Unix.
  6. ** CPSC 414 Assignment No. 4 Project
  7. **  
  8. ** Programmed by Bradley Head and Thomas Burkholder 
  9. ** December 1990
  10. */
  11.  
  12. #import "proj.h"
  13. #import "pointdata.h"
  14. #import "appkit/graphics.h"
  15.  
  16. /********************* THE MAP PROJECTIONS (Forward Sol'n) **********************************/
  17.  
  18. float correct(float f)
  19. {
  20.     if (f>=PI)
  21.         return f-(2*PI);
  22.     if (f < (-(PI)))
  23.         return f+(2*PI);
  24.     return f;
  25. }
  26.  
  27. /*
  28. **  Map Projection conversion functions 
  29. */
  30.  
  31. int Cylindrical(Point *posn, ProjParam *init, Point *pp)
  32. float coef;
  33.  
  34. coef = init->radius*cos(init->phi1);
  35. pp->x = (posn->x - init->lon0)*coef;
  36. pp->y = init->radius*sin(posn->y)/cos(init->phi1);
  37. if (pp->x > (PI*coef)) {
  38.     pp->x -= ((2*PI)*coef);
  39.     return 1;
  40.     }
  41. if (pp->x < ((-(PI))*coef)) {
  42.     pp->x += ((2*PI)*coef);
  43.     return 1;
  44.     }
  45. return 0;
  46. }
  47.  
  48.  
  49. int EckertIV(Point *posn, ProjParam *init, Point *pp)
  50. float coef;
  51.  
  52. coef = .42224*init->radius*(1 + cos(posn->y - init->phi1));
  53. pp->x = coef*(posn->x - init->lon0);
  54. pp->y = 1.32650*init->radius*sin(posn->y - init->phi1)/cos(init->phi1);
  55.  
  56. if (pp->x  > (PI*coef)) {
  57.     pp->x -= ((2*PI)*coef);
  58.     return 1;
  59.     }
  60. if (pp->x < ((-(PI))*coef)) {
  61.     pp->x += ((2*PI)*coef);
  62.     return 1;
  63.     } 
  64. return 0;
  65. }
  66.  
  67. int Mercator(Point *posn, ProjParam *init, Point *pp)
  68. {
  69. float coef;
  70.  
  71. coef = init->radius*0.6;            /* 0.6 scales to fit into output window with radius = 1.0 */
  72. pp->x =coef*(posn->x - init->lon0);
  73. pp->y = init->radius*log(tan(.785398 + posn->y/2));
  74. if (pp->x > (PI*coef)) {
  75.     pp->x -= ((2*PI)*coef);
  76.     return 1;
  77.     }
  78. if (pp->x < ((-(PI))*coef)) {
  79.     pp->x += ((2*PI)*coef);
  80.     return 1;
  81.     }
  82. return 0;
  83. }
  84.  
  85. int Mollweide(Point *posn, ProjParam *init, Point *pp)
  86. float coef;
  87.  
  88. coef = .9003*init->radius*cos(posn->y - init->phi1);
  89. pp->x = (posn->x - init->lon0)*coef;
  90. pp->y = 1.4142*init->radius*sin(posn->y - init->phi1);
  91. if (pp->x > (PI*coef)) {
  92.     pp->x -= ((2*PI)*coef);
  93.     return 1;
  94.     }
  95. if (pp->x < ((-(PI))*coef)) {
  96.     pp->x += ((2*PI)*coef);
  97.     return 1;
  98.     }
  99. return 0;
  100.  
  101. int Ortho(Point *posn, ProjParam *init, Point *pp)
  102. {
  103. float cos_c;
  104. float dl; 
  105. dl = posn->x  - init->lon0;
  106.  
  107. pp->x = init->radius*cos(posn->y)*sin(dl); 
  108. if ((posn->y != -PI) && (posn->y != PI))
  109.     pp->y = init->radius*(cos(init->phi1)*sin(posn->y) - 
  110.     sin(init->phi1)*cos(posn->y)*cos(dl));
  111. else
  112.     pp->y = init->radius*cos(posn->y)*cos(dl);
  113. if (posn->y == PI)                            /* conditionals for line removal */
  114.     pp->y = - pp->y;
  115. cos_c = sin(init->phi1)*sin(posn->y)+cos(init->phi1)*cos(posn->y)*cos(dl);
  116. if (cos_c < 0)
  117.     pp->pen = SKIP;
  118. return 0;
  119.  
  120.  
  121. int Sinusoidal(Point *posn, ProjParam *init, Point *pp)
  122. {
  123. float coef;
  124. float xofs;
  125.  
  126. coef = init->radius*cos(posn->y - init->phi1);
  127. pp->x = (posn->x - init->lon0)*coef ; 
  128. pp->y = init->radius*(posn->y - init->phi1);
  129. if (pp->x > (PI*coef)) {            /* clipping conditonals for animation */
  130.     pp->x -= ((2*PI)*coef);
  131.     return 1;
  132.     }
  133. if (pp->x < ((-(PI))*coef)) {        /* conditionals for animation */
  134.     pp->x += ((2*PI)*coef);
  135.     return 1;
  136.     }
  137. return 0;
  138. }
  139.  
  140.  
  141. int Stereo(Point *posn, ProjParam *init, Point *pp)
  142. float dl,k,r; 
  143. float Len;
  144. dl = posn->x - init->lon0;
  145. r = init->radius*0.6;
  146. k = 2/(1+sin(init->phi1)*sin(posn->y)+cos(init->phi1)*cos(posn->y)*cos(dl));
  147. pp->x = r*k*cos(posn->y)*sin(dl);
  148. pp->y = r*k*(cos(init->phi1)*sin(posn->y) - sin(init->phi1)*cos(posn->y)*cos(dl));
  149. Len = sqrt((pp->x)*(pp->x) + (pp->y)*(pp->y));
  150. if (Len > init->radius*1.2)
  151.     pp->pen = SKIP;
  152. return 0;
  153. }
  154.  
  155. int None(Point *posn, ProjParam *init, Point *pp)
  156. float dl; 
  157. float Len;
  158. float coef;
  159. coef = init->radius;
  160. dl = posn->x - init->lon0;
  161. pp->x = coef*dl;
  162. pp->y =  coef*(posn->y - init->phi1);
  163. if (pp->x > (PI*coef)) {            /* clipping condtionals for animation */
  164.     pp->x -= ((2*PI)*coef);
  165.     return 1;
  166.     }
  167. if (pp->x < ((-(PI))*coef)) {
  168.     pp->x += ((2*PI)*coef);
  169.     return 1;
  170.     }
  171. return 0;
  172. }
  173.  
  174.  /****************************************************/ 
  175.  
  176.  void DoFrame(PointList *framelist) {
  177.  /*
  178.  **  This function creates two frame lines 
  179.  **   for the projections
  180.  **   all except stereographic and orthographic
  181.  */        
  182.   float lat, lon;
  183.  Point framept;
  184.  framept.pencolour = NX_DKGRAY;
  185.    for (lon = -180;lon <= 180;lon += 360) {
  186.      for (lat = -75;lat <= 75;lat += 5)  {
  187.         if (lat == 75)
  188.             framept.pen = UP;
  189.         else
  190.             framept.pen = DOWN;
  191.         framept.y = lat *toRADS;
  192.         framept.x = lon *toRADS;
  193.         addToPointList(framelist ,&framept);
  194.         }
  195.     }
  196.  }
  197.  
  198.  void  drawCircleFrame(float radius, PointList *pout) {
  199.  /* 
  200.  ** This function generates
  201.  ** a framing circle
  202.  ** around stereographic and
  203.  ** the orthographic
  204.  ** projections.
  205.  */
  206.  Point p;
  207.  float  step, x;
  208.  p.pencolour = NX_DKGRAY;
  209.  step = radius/100.0;
  210.  for (x = -radius;x <= radius;x += step) {    /* to top half of circle */
  211.      p.y = sqrt(radius*radius - x*x);
  212.     p.x = x;
  213.     p.pen = DOWN;
  214.     addToPointList(pout,&p);
  215.     }
  216.  for (x = radius-step;x >= (-radius+step); x -= step) {  /* do bottom half */
  217.     p.y = -(sqrt(radius*radius - x*x));
  218.     p.x = x;
  219.     p.pen = DOWN;
  220.     addToPointList(pout,&p);
  221.     }
  222. p.y = 0.0;
  223. p.x = -radius;
  224. p.pen = UP;
  225. addToPointList(pout,&p); 
  226.  }
  227.  
  228. /****************************************************/
  229.  
  230. void DoGrid(PointList *gridlist) {
  231. /*
  232. ** This function generates the graticules
  233. ** for the output view 
  234. ** for all the projections
  235. ** it increments at 15 degree intervals
  236. */
  237. int lat, lon;
  238. Point  gridpt ;
  239.  
  240. gridpt.pencolour = NX_LTGRAY;
  241. gridpt.pen = DOWN;
  242. /*  
  243. ** Compute the lines of latitude
  244. */
  245.  
  246. for (lat = -75;lat <= 75;lat += 15) { 
  247.     for (lon = -180;lon <= 180; lon += 5)
  248.         { 
  249.         if (lon == 180 )
  250.             gridpt.pen = UP;
  251.         else 
  252.             gridpt.pen = DOWN;
  253.         gridpt.y = lat *toRADS;
  254.         gridpt.x = lon *toRADS;
  255.         addToPointList(gridlist,&gridpt);
  256.         }
  257.     } 
  258. /*  
  259. ** Now compute the Meridians
  260. */
  261.  
  262. for (lon =  -180;lon < 180; lon += 15) {
  263.     for (lat = -75;lat <= 75;lat += 5 ) 
  264.         {
  265.         if (lat == 75)
  266.             gridpt.pen = UP;
  267.         else
  268.             gridpt.pen = DOWN;
  269.         gridpt.y = lat *toRADS;
  270.         gridpt.x = lon *toRADS;
  271.         addToPointList(gridlist,&gridpt);
  272.         }
  273.     } 
  274. }
  275.  
  276. void ComputePoints(int (*proj)(Point *posn, ProjParam *init, Point *pp), ProjParam *init,PointList *inlist,PointList *outlist)
  277. {
  278. /* 
  279. ** This function computes the output
  280. ** points given the input list of  (lat,lon) pairs
  281. ** it  calls the appropriate map projection routine
  282. ** determines line clipping in the form of skipping
  283. ** unnecessary points (points that won't be drawn to output)
  284. ** It places the computed points in an outlist list of points
  285. ** that can then be plotted
  286. */
  287. int i ;
  288. int oldsplit,split;
  289. Point pp, old;
  290. Point *pt;
  291. int a =1;
  292. old.pen = UP;
  293. oldsplit = 1;
  294. for (i = gotoPointInList(inlist,0,&pt);(i);i=gotoNextPointInList(inlist,&pt))    
  295.     {
  296.     
  297.     pp = *pt;
  298.     split = (*proj)(pt,init,&pp);
  299.     if ((old.pen == DOWN) && (pp.pen == SKIP)) 
  300.         old.pen = UP;
  301.     if (split  != oldsplit)
  302.         old.pen = UP;
  303.     if (a) 
  304.         a = 0;
  305.     else
  306.         addToPointList(outlist,&old);
  307.     old = pp;
  308.     oldsplit = split;
  309.     }
  310. if (inlist->quantity) {
  311.     pp.pen = UP;
  312.     addToPointList(outlist,&pp);
  313.     }
  314. }
  315.  
  316. int convertPoints(PointList *pin, PointList *pout, int gridon, ProjParam *init)
  317. {
  318. /* This function is the externally called function
  319. ** It handles whether to compute and draw the 
  320. ** grid and frames and computes the output points
  321. ** by calliing ComputePoints with the appropriate 
  322. ** map projection.
  323. */
  324. PointList grid, frame;        /* point list for the frame around the projection */
  325. ProjParam frameparam;        /* frame drawing initialization paramaters */
  326.  
  327. frameparam.radius  = init->radius;    /* get the current radius */
  328. frameparam.lon0 = 0.0;            /* fix the central meridian for frame computation */
  329. frameparam.phi1 = init->phi1;    /* get the current central line of latitude */
  330.  
  331. init->lon0 = correct(init->lon0);    /* correct the offset for animation */
  332. newPointList(&grid);            /* generate a new list for the grid */
  333. newPointList(&frame);            /* generate a new list for the frame */
  334. DoFrame(&frame);                /* compute the frame */
  335. if (gridon)                        
  336.     DoGrid(&grid);            /* if want the grid displayed then compute the grid */
  337.  
  338. switch (init->proj)                /* select the appropriate projection to compute */
  339.     {
  340.     case CYLINDER: 
  341.         ComputePoints(&Cylindrical,init,&grid,pout);
  342.         ComputePoints(&Cylindrical,&frameparam,&frame,pout);
  343.         ComputePoints(&Cylindrical,init,pin,pout);
  344.         break;
  345.     case ECKERT:  
  346.         ComputePoints(&EckertIV,init,&grid,pout);
  347.         ComputePoints(&EckertIV,&frameparam,&frame,pout);
  348.         ComputePoints(&EckertIV,init,pin,pout);
  349.         break;
  350.     case MERCATOR: 
  351.         ComputePoints(&Mercator,init,&grid,pout);
  352.         ComputePoints(&Mercator,&frameparam,&frame,pout);
  353.         ComputePoints(&Mercator,init,pin,pout);
  354.         break;
  355.     case MOLLWEIDE:  
  356.         ComputePoints(&Mollweide,init,&grid,pout);
  357.         ComputePoints(&Mollweide,&frameparam,&frame,pout);
  358.         ComputePoints(&Mollweide,init,pin,pout);
  359.         break;
  360.     case ORTHO: 
  361.         ComputePoints(&Ortho,init,&grid,pout);
  362.         drawCircleFrame(init->radius,pout);
  363.         ComputePoints(&Ortho,init,pin,pout); 
  364.         break;
  365.     case SINUSOIDAL: 
  366.         ComputePoints(&Sinusoidal,init,&grid,pout);
  367.         ComputePoints(&Sinusoidal,&frameparam,&frame,pout);
  368.         ComputePoints(&Sinusoidal,init,pin, pout);
  369.         break;
  370.     case STEREO: 
  371.         ComputePoints(&Stereo,init,&grid,pout);
  372.         drawCircleFrame(init->radius*1.2, pout);
  373.         ComputePoints(&Stereo,init,pin,pout);
  374.         break;
  375.     case NONE:
  376.         ComputePoints(&None,init,&grid,pout);
  377.         ComputePoints(&None,init,pin,pout);
  378.         break;
  379.     default: break;
  380.     }
  381. return 1;
  382. }
  383.  
  384.  
  385.